#!/usr/bin/env python3
"""
日志查看器
用于查看和分析代理服务器的日志
"""

import json
import os
import glob
from datetime import datetime
from typing import List, Dict, Any
import argparse
import sys
import io

class LogViewer:
    """日志查看器"""
    
    def __init__(self, logs_dir: str = "logs/requests"):
        self.logs_dir = logs_dir
    
    def get_log_files(self) -> List[Dict[str, Any]]:
        """获取所有日志文件"""
        if not os.path.exists(self.logs_dir):
            return []
        
        log_files = []
        for file_path in glob.glob(os.path.join(self.logs_dir, "*.json")):
            stat = os.stat(file_path)
            log_files.append({
                "path": file_path,
                "filename": os.path.basename(file_path),
                "size": stat.st_size,
                "modified": datetime.fromtimestamp(stat.st_mtime),
                "type": "request" if "request" in file_path else "response"
            })
        
        # 按修改时间排序
        log_files.sort(key=lambda x: x["modified"], reverse=True)
        return log_files
    
    def load_log_file(self, file_path: str) -> Dict[str, Any]:
        """加载日志文件"""
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception as e:
            return {"error": f"加载文件失败: {e}"}
    
    def get_request_pairs(self) -> List[Dict[str, Any]]:
        """获取请求-响应对"""
        log_files = self.get_log_files()
        
        # 按请求ID分组
        request_groups = {}
        for log_file in log_files:
            # 从文件名中提取请求ID和类型
            filename = log_file["filename"]
            if "_request.json" in filename:
                request_id = filename.replace("_request.json", "")
                if request_id not in request_groups:
                    request_groups[request_id] = {}
                request_groups[request_id]["request"] = log_file["path"]
            elif "_response.json" in filename:
                request_id = filename.replace("_response.json", "")
                if request_id not in request_groups:
                    request_groups[request_id] = {}
                request_groups[request_id]["response"] = log_file["path"]
        
        # 构建请求-响应对
        pairs = []
        for request_id, files in request_groups.items():
            if "request" in files and "response" in files:
                request_data = self.load_log_file(files["request"])
                response_data = self.load_log_file(files["response"])
                
                pairs.append({
                    "request_id": request_id,
                    "request": request_data,
                    "response": response_data,
                    "timestamp": request_data.get("timestamp", ""),
                    "method": request_data.get("method", ""),
                    "url": request_data.get("url", ""),
                    "status_code": response_data.get("status_code", 0)
                })
        
        # 按时间排序
        pairs.sort(key=lambda x: x["timestamp"], reverse=True)
        return pairs
    
    def print_summary(self):
        """打印日志摘要"""
        log_files = self.get_log_files()
        pairs = self.get_request_pairs()
        
        print("=" * 60)
        print("OpenAI API代理服务器日志摘要")
        print("=" * 60)
        print(f"日志文件总数: {len(log_files)}")
        print(f"完整请求-响应对: {len(pairs)}")
        
        if pairs:
            print(f"最新请求时间: {pairs[0]['timestamp']}")
            print(f"最早请求时间: {pairs[-1]['timestamp']}")
            
            # 统计状态码
            status_codes = {}
            response_types = {}
            models = {}
            
            for pair in pairs:
                status = pair["status_code"]
                status_codes[status] = status_codes.get(status, 0) + 1
                
                response_type = pair["response"].get("response_type", "unknown")
                response_types[response_type] = response_types.get(response_type, 0) + 1
                
                model = pair["response"].get("model", "unknown")
                if model != "unknown":
                    models[model] = models.get(model, 0) + 1
            
            print("\n状态码统计:")
            for status, count in sorted(status_codes.items()):
                print(f"  {status}: {count}次")
            
            print("\n响应类型统计:")
            for rtype, count in sorted(response_types.items()):
                print(f"  {rtype}: {count}次")
            
            if models:
                print("\n模型使用统计:")
                for model, count in sorted(models.items()):
                    print(f"  {model}: {count}次")
        
        print("=" * 60)
    
    def print_recent_requests(self, limit: int = 10):
        """打印最近的请求"""
        pairs = self.get_request_pairs()
        
        print(f"\n最近 {min(limit, len(pairs))} 个请求:")
        print("-" * 60)
        
        for i, pair in enumerate(pairs[:limit]):
            print(f"{i+1}. 请求ID: {pair['request_id']}")
            print(f"   时间: {pair['timestamp']}")
            print(f"   方法: {pair['method']}")
            print(f"   URL: {pair['url']}")
            print(f"   状态码: {pair['status_code']}")
            
            # 显示请求内容摘要
            if "body" in pair["request"] and pair["request"]["body"]:
                body = pair["request"]["body"]
                if isinstance(body, dict):
                    if "model" in body:
                        print(f"   请求模型: {body['model']}")
                    if "messages" in body and body["messages"]:
                        # 分析消息内容，提取工具调用信息
                        self._analyze_messages(body["messages"])
            
            # 显示响应内容摘要
            if "response_type" in pair["response"]:
                if pair["response"]["response_type"] == "stream":
                    print(f"   响应类型: 流式")
                    print(f"   响应模型: {pair['response'].get('model', 'N/A')}")
                    content = pair["response"].get("content", "")[:100]
                    if content:
                        print(f"   回复内容: {content}...")
                    usage = pair["response"].get("usage", {})
                    if usage:
                        input_tokens = usage.get("input_tokens", 0)
                        output_tokens = usage.get("output_tokens", 0)
                        print(f"   Token使用: 输入{input_tokens}, 输出{output_tokens}")
                else:
                    print(f"   响应类型: 普通")
                    if "body" in pair["response"]:
                        body = pair["response"]["body"]
                        if isinstance(body, str) and len(body) > 100:
                            print(f"   响应内容: {body[:100]}...")
                        else:
                            print(f"   响应内容: {body}")
            
            print()
    
    def _analyze_messages(self, messages):
        """分析消息内容，提取工具调用信息"""
        tool_calls = []
        tool_results = []
        text_messages = []
        
        for msg in messages:
            if msg.get("role") == "assistant":
                content = msg.get("content", [])
                if isinstance(content, list):
                    for item in content:
                        if item.get("type") == "tool_use":
                            tool_calls.append({
                                "name": item.get("name", "unknown"),
                                "id": item.get("id", "unknown"),
                                "input": item.get("input", {})
                            })
                        elif item.get("type") == "text":
                            text = item.get("text", "")
                            if text.strip():
                                text_messages.append(text[:100] + "..." if len(text) > 100 else text)
            elif msg.get("role") == "user":
                content = msg.get("content", [])
                if isinstance(content, list):
                    for item in content:
                        if item.get("type") == "tool_result":
                            tool_results.append({
                                "tool_use_id": item.get("tool_use_id", "unknown"),
                                "content": item.get("content", "")[:100] + "..." if len(item.get("content", "")) > 100 else item.get("content", "")
                            })
                        elif item.get("type") == "text":
                            text = item.get("text", "")
                            if text.strip():
                                text_messages.append(text[:100] + "..." if len(text) > 100 else text)
        
        # 显示文本消息
        if text_messages:
            print(f"   对话内容: {len(text_messages)} 条消息")
            for j, text in enumerate(text_messages[:3]):  # 只显示前3条
                print(f"     {j+1}. {text}")
            if len(text_messages) > 3:
                print(f"     ... 还有 {len(text_messages) - 3} 条消息")
        
        # 显示工具调用统计
        if tool_calls:
            print(f"   工具调用: {len(tool_calls)} 次")
            tool_types = {}
            for tool in tool_calls:
                name = tool["name"]
                tool_types[name] = tool_types.get(name, 0) + 1
            
            for tool_name, count in tool_types.items():
                print(f"     - {tool_name}: {count} 次")
        
        if tool_results:
            print(f"   工具结果: {len(tool_results)} 个")
    
    def view_request_detail(self, request_id: str):
        """查看特定请求的详细信息"""
        pairs = self.get_request_pairs()
        
        for pair in pairs:
            if pair["request_id"] == request_id:
                print(f"请求详情 - {request_id}")
                print("=" * 60)
                
                print("请求信息:")
                print(json.dumps(pair["request"], ensure_ascii=False, indent=2))
                
                print("\n响应信息:")
                print(json.dumps(pair["response"], ensure_ascii=False, indent=2))
                return
        
        print(f"未找到请求ID: {request_id}")
    
    def view_tool_calls(self, request_id: str):
        """查看特定请求的工具调用详情"""
        pairs = self.get_request_pairs()
        
        for pair in pairs:
            if pair["request_id"] == request_id:
                print(f"工具调用详情 - {request_id}")
                print("=" * 60)
                
                if "body" in pair["request"] and pair["request"]["body"]:
                    body = pair["request"]["body"]
                    if isinstance(body, dict) and "messages" in body:
                        self._print_detailed_tool_calls(body["messages"])
                return
        
        print(f"未找到请求ID: {request_id}")
    
    def _print_detailed_tool_calls(self, messages):
        """打印详细的工具调用信息"""
        conversation_steps = []
        tool_results = {}  # 存储工具调用结果
        
        for i, msg in enumerate(messages):
            if msg.get("role") == "assistant":
                content = msg.get("content", [])
                if isinstance(content, list):
                    for item in content:
                        if item.get("type") == "text":
                            text = item.get("text", "").strip()
                            if text:  # 显示所有文本内容
                                conversation_steps.append(f"🤖 助手: {text}")
                        elif item.get("type") == "tool_use":
                            tool_name = item.get("name", "unknown")
                            tool_id = item.get("id", "unknown")
                            tool_input = item.get("input", {})
                            
                            # 构建简化的参数显示
                            param_str = ""
                            if tool_name == "Write":
                                file_path = tool_input.get("file_path", "unknown")
                                content_preview = tool_input.get("content", "")[:50] + "..." if len(tool_input.get("content", "")) > 50 else tool_input.get("content", "")
                                param_str = f"file_path: {file_path}, content: {content_preview}"
                            elif tool_name == "Read":
                                file_path = tool_input.get("file_path", "unknown")
                                param_str = f"file_path: {file_path}"
                            elif tool_name == "Edit":
                                file_path = tool_input.get("file_path", "unknown")
                                param_str = f"file_path: {file_path}"
                            elif tool_name == "Bash":
                                command = tool_input.get("command", "unknown")
                                description = tool_input.get("description", "")
                                param_str = f"command: {command}"
                                if description:
                                    param_str += f", description: {description}"
                            elif tool_name == "TodoWrite":
                                todos = tool_input.get("todos", [])
                                param_str = f"todos: {len(todos)} 项"
                            
                            conversation_steps.append(f"🔧 工具调用 [{tool_id}]: {tool_name}({param_str})")
            
            elif msg.get("role") == "user":
                content = msg.get("content", [])
                if isinstance(content, list):
                    for item in content:
                        if item.get("type") == "text":
                            text = item.get("text", "").strip()
                            if text:  # 显示所有文本内容
                                conversation_steps.append(f"👤 用户: {text}")
                        elif item.get("type") == "tool_result":
                            tool_use_id = item.get("tool_use_id", "unknown")
                            result_content = item.get("content", "")
                            
                            conversation_steps.append(f"✅ 工具结果 [{tool_use_id}]:")
                            conversation_steps.append(f"   返回内容: {result_content}")
                            
                            # 存储工具结果以便后续关联
                            tool_results[tool_use_id] = result_content
        
        # 打印完整的对话流程
        print("💬 完整对话流程:")
        print("=" * 60)
        for i, step in enumerate(conversation_steps):
            print(f"{i+1:3d}. {step}")
        
        print(f"\n📊 统计信息:")
        print(f"  总对话步骤: {len(conversation_steps)}")
        print(f"  工具调用结果: {len(tool_results)} 个")

def main():
    # 确保控制台输出为UTF-8，避免在Windows下打印emoji/中文时报编码错误
    try:
        if hasattr(sys.stdout, "reconfigure"):
            sys.stdout.reconfigure(encoding="utf-8", errors="replace")
        else:  # 兼容老版本Python
            sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")  # type: ignore
    except Exception:
        pass

    parser = argparse.ArgumentParser(description="OpenAI API代理日志查看器")
    parser.add_argument("--summary", action="store_true", help="显示日志摘要")
    parser.add_argument("--recent", type=int, default=10, help="显示最近的N个请求")
    parser.add_argument("--detail", type=str, help="查看特定请求ID的详细信息")
    parser.add_argument("--tools", type=str, help="查看特定请求ID的工具调用详情")
    parser.add_argument("--logs-dir", default="logs/requests", help="日志目录路径")
    parser.add_argument("--output", type=str, help="将输出写入指定文件而不是控制台")
    parser.add_argument("--encoding", default="utf-8", help="输出文件编码，默认utf-8")
    
    args = parser.parse_args()
    
    viewer = LogViewer(args.logs_dir)

    # 如果指定了输出文件，则将标准输出重定向到文件
    file_handle = None
    if args.output:
        try:
            file_handle = open(args.output, "w", encoding=args.encoding, newline="")
            sys.stdout = file_handle  # type: ignore
        except Exception as e:
            print(f"无法打开输出文件: {e}")
            return
    
    try:
        if args.detail:
            viewer.view_request_detail(args.detail)
        elif args.tools:
            viewer.view_tool_calls(args.tools)
        else:
            viewer.print_summary()
            viewer.print_recent_requests(args.recent)
    finally:
        if file_handle:
            try:
                file_handle.close()
            except Exception:
                pass

if __name__ == "__main__":
    main() 